/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.rpgmapper.manager;

import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.input.InputManager;
import com.jme3.input.MouseInput;
import com.jme3.input.TouchInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.controls.MouseAxisTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.input.controls.TouchListener;
import com.jme3.input.controls.TouchTrigger;
import com.jme3.input.event.TouchEvent;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
import java.util.ArrayList;
import java.util.List;
import org.rpgmapper.tools.AppContext;

/**
 *
 * @author Nehon
 */
public class SelectionManager {

    private Camera cam;
    private List<CellSelectionChangeListener> cellListeners = new ArrayList<CellSelectionChangeListener>();
    private List<CharacterSelectionListener> characterListeners = new ArrayList<CharacterSelectionListener>();
    private Mode mode = Mode.Character;
    private boolean drawing = false;
    private float savedX = 0, savedY = 0;

    public enum Mode {

        Cell,
        Character,
        Draw
    }

    public SelectionManager(Camera cam, final InputManager inputManager) {

        this.cam = cam;//AppContext.getRtsCam().getCamera();

        inputManager.addListener(new ActionListener() {

            public void onAction(String name, boolean isPressed, float tpf) {
                if (name.equals("click") && isPressed) {
                    TempVars vars = TempVars.get();
                    if (mode == Mode.Cell || mode == Mode.Draw) {
                        drawing = mode == Mode.Draw;
                        pick(inputManager.getCursorPosition(), AppContext.getMapManager().getGroundGeometry(), vars.vect2d2);
                    } else {
                        pick(inputManager.getCursorPosition(), AppContext.getMapManager().getCharactersNode(), vars.vect2d2);
                    }
                    vars.release();
                }
                if (name.equals("click") && !isPressed) {
                    if (mode == Mode.Draw) {
                        drawing = false;
                        AppContext.getMapManager().getDrawingManager().quitDrawing();
                    }
                }
            }
        }, "click");

        inputManager.addListener(new AnalogListener() {

            public void onAnalog(String name, float value, float tpf) {
                if (name.equals("draw") && drawing) {
                    TempVars vars = TempVars.get();
                    pick(inputManager.getCursorPosition(), AppContext.getMapManager().getGroundGeometry(), vars.vect2d2);
                    vars.release();
                }
            }
        }, "draw");



        inputManager.addMapping("click", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
        inputManager.addMapping("draw", new MouseAxisTrigger(MouseInput.AXIS_X, false), new MouseAxisTrigger(MouseInput.AXIS_X, true), new MouseAxisTrigger(MouseInput.AXIS_Y, false), new MouseAxisTrigger(MouseInput.AXIS_Y, true));


        inputManager.addListener(new TouchListener() {

            public void onTouch(String name, TouchEvent event, float tpf) {
                //System.out.println(event.getType());
                if (event.getType() == TouchEvent.Type.TAP) {
                    TempVars vars = TempVars.get();
                    vars.vect2d.set(event.getX(), event.getY());
                    if (mode == Mode.Cell) {
                        //   System.out.println("pick");
                        pick(vars.vect2d, AppContext.getMapManager().getGroundGeometry(), null);
                    } else if (mode == Mode.Character) {
                        pick(vars.vect2d, AppContext.getMapManager().getCharactersNode(), null);
                    }
                    vars.release();
                }
                if (event.getType() == TouchEvent.Type.SCROLL) {
                    if (mode == Mode.Draw) {
                        TempVars vars = TempVars.get();
                        savedX -= event.getDeltaX();
                        savedY -= event.getDeltaY();
                        vars.vect2d.set(savedX, savedY);
                        //System.err.println(savedX + "," + savedY);
                        pick(vars.vect2d, AppContext.getMapManager().getGroundGeometry(), vars.vect2d2);

                        vars.release();
                    }
                }


                if (event.getType() == TouchEvent.Type.DOWN) {
                    if (mode == Mode.Draw) {
                        TempVars vars = TempVars.get();
                        savedX = event.getX();
                        savedY = event.getY();
                        vars.vect2d.set(savedX, savedY);

                        pick(vars.vect2d, AppContext.getMapManager().getGroundGeometry(), vars.vect2d2);

                        vars.release();
                    }
                }

                if (event.getType() == TouchEvent.Type.UP) {
                    if (mode == Mode.Draw) {
                        AppContext.getMapManager().getDrawingManager().quitDrawing();
                    }
                }
            }
        },
                "tap");


        inputManager.addMapping("tap", new TouchTrigger(TouchInput.ALL));
    }

    private void pick(Vector2f coord, Spatial node, Vector2f tmpVec) {
        Vector3f origin = cam.getWorldCoordinates(coord, 0.0f);
        Vector3f direction = cam.getWorldCoordinates(coord, 0.3f);
        direction.subtractLocal(origin).normalizeLocal();

        Ray ray = new Ray(origin, direction);
        CollisionResults results = new CollisionResults();
        Vector3f contactPoint = null;
        node.collideWith(ray, results);
        if (mode == Mode.Cell) {
            int index = 0;
            if (results.size() > 0) {
                CollisionResult closest = results.getClosestCollision();
                contactPoint = closest.getContactPoint();
                index = AppContext.getMapManager().getIndex(contactPoint);
            } else {
                index = -1;
            }
            for (CellSelectionChangeListener listener : cellListeners) {
                listener.onSelectionChange(index, contactPoint);
            }
        } else if (mode == Mode.Character) {
            if (results.size() > 0) {
                CollisionResult closest = results.getClosestCollision();
                Geometry g = closest.getGeometry();
                //System.out.println(g.getName());
                for (CharacterSelectionListener listener : characterListeners) {
                    listener.onCharacterSelect(getNodeName(g));
                }
            }
        } else {
            // int index = 0;
            if (results.size() > 0) {
                CollisionResult closest = results.getClosestCollision();
                contactPoint = closest.getContactPoint();
                //  System.out.println(contactPoint);
                Vector2f vect = AppContext.getMapManager().getPixel(contactPoint, tmpVec);
                AppContext.getMapManager().getDrawingManager().draw(vect);

//                System.out.println("vect "+vect);
//                System.out.println("tmpVect "+tmpVec);

            }
//            for (CellSelectionChangeListener listener : cellListeners) {
//                listener.onSelectionChange(index, contactPoint);
//            }
        }


    }

    private String getNodeName(Spatial s) {

        Spatial s2 = s;
        String name = s2.getName();
        while (!s2.getName().equals(AppContext.getMapManager().getCharactersNode().getName())) {
            name = s2.getName();
            s2 = s2.getParent();
            while (s2.getName() == null) {
                s2 = s2.getParent();
            }
        }
        return name;
    }

    public Mode getMode() {
        return mode;
    }

    public void setMode(Mode mode) {
        this.mode = mode;
    }

    public void addCellListener(CellSelectionChangeListener listener) {
        cellListeners.add(listener);
    }

    public void removeCellListener(CellSelectionChangeListener listener) {
        cellListeners.remove(listener);
    }

    public void addCharacterListener(CharacterSelectionListener listener) {
        characterListeners.add(listener);
    }

    public void removeCharacterListener(CharacterSelectionListener listener) {
        characterListeners.remove(listener);
    }
}
